﻿//
// Created by LiuYou on 2021/4/25.
//

//#include <cstdio>
#include <cstring>
#include <unistd.h>
//#include <cstdlib>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string>
#include <iostream>

int main(int argc, char** argv) {
    if (argc != 2) {
        std::cout << "Using:./server port" << std::endl
                  << "Example:./server 5005" << std::endl;
//        printf("Using:./server port\nExample:./server 5005\n\n");
        return -1;
    }

    // 第1步：创建服务端的socket。
    int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == -1) {
        perror("socket");
        return -1;
    }

    // 第2步：把服务端用于通信的地址和端口绑定到socket上。

/*    // 服务端地址信息的数据结构。
    sockaddr_in serverAddress{};
    // TODO 不知道什么意思？
    memset(&serverAddress, 0, sizeof(serverAddress));
    // 协议族，在socket编程中只能是AF_INET。
    serverAddress.sin_family = AF_INET;
    // 任意ip地址。
    serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
    // 指定ip地址。
//    serverAddress.sin_addr.s_addr = inet_addr("192.168.190.134");
    // 指定通信端口。
    std::string portStr(argv[1]);
    serverAddress.sin_port = htons(std::stoul(portStr));
//    serverAddress.sin_port = htons(atoi(argv[1]));*/
    std::string portStr(argv[1]);
    sockaddr_in serverAddress{
            .sin_family=AF_INET,
            .sin_port=htons(std::stoul(portStr)),
            {.s_addr=htonl(INADDR_ANY)}
    };

    // TODO 这里不能使用新式的C++强转static_cast<sockaddr*>(&serverAddress) , 是直接报错的！！！！ 我不知道为什么？
    int bindReturnValue = bind(serverSocket, (sockaddr*) &serverAddress, sizeof(serverAddress));
    if (bindReturnValue != 0) {
        perror("bind");
        close(serverSocket);
        return -1;
    }

    // 第3步：把socket设置为监听模式。
    int listenReturnValue = listen(serverSocket, 5);
    if (listenReturnValue != 0) {
        perror("listen");
        close(serverSocket);
        return -1;
    }

    // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    // 第4步：接受客户端的连接。
/*    int acceptReturnValue;                  // 客户端的socket。
    int socklen = sizeof(struct sockaddr_in); // struct sockaddr_in的大小
    sockaddr_in clientAddress;  // 客户端的地址信息。
    acceptReturnValue = accept(serverSocket, (struct sockaddr*) &clientAddress, (socklen_t*) &socklen);*/


    // struct sockaddr_in的大小
    int socklen = sizeof(sockaddr_in);
    // 客户端的地址信息。
    sockaddr_in clientAddress{};
    // 客户端的socket。
    int acceptReturnValue = accept(serverSocket, (sockaddr*) &clientAddress, (socklen_t*) &socklen);

    std::cout << "客户端(" << inet_ntoa(clientAddress.sin_addr) << ")已连接。" << std::endl;
//    printf("客户端（%s）已连接。\n", inet_ntoa(clientAddress.sin_addr));

/*    // 第5步：与客户端通信，接收客户端发过来的报文后，回复ok。
    char buffer[1024];
    while (true) {
        memset(buffer, 0, sizeof(buffer));
        // 接收客户端的请求报文。
        ssize_t recvReturnValue = recv(acceptReturnValue, buffer, sizeof(buffer), 0);
        if (recvReturnValue <= 0) {
            std::cout << "recvReturnValue=" << recvReturnValue << std::endl;
//            printf("iret=%zd\n", recvReturnValue);
            break;
        }
        std::cout << "接受: " << *buffer << std::endl;
//        printf("接收：%s\n", buffer);

        strcpy(buffer, "ok");
        // 向客户端发送响应结果。
        ssize_t sendReturnValue = send(acceptReturnValue, buffer, strlen(buffer), 0);
        if (sendReturnValue <= 0) {
            perror("send");
            break;
        }
        std::cout << "发送: " << *buffer << std::endl;
//        printf("发送：%s\n", buffer);
    }*/

    // 第5步：与客户端通信，接收客户端发过来的报文后，回复ok。
    char buffer[1024];
    while (true) {
        memset(buffer, 0, sizeof(buffer));
        // 接收客户端的请求报文。
        ssize_t recvReturnValue = recv(acceptReturnValue, buffer, sizeof(buffer), 0);
        if (recvReturnValue <= 0) {
            std::cout << "recvReturnValue=" << recvReturnValue << std::endl;
//            printf("iret=%zd\n", recvReturnValue);
            break;
        }
        std::cout << "接受: " << std::string(buffer) << std::endl;

        strcpy(buffer, "ok");
        // 向客户端发送响应结果。
        ssize_t sendReturnValue = send(acceptReturnValue, buffer, strlen(buffer), 0);
        if (sendReturnValue <= 0) {
            perror("send");
            break;
        }
        std::cout << "发送: " << std::string(buffer) << std::endl;
    }

// TODO 注意: 还是使用C的原始数组和原始指针吧！！！！通过资料查阅在C++的boost库中有一个asio库, 这个库封装了原始的socket。所以如果不使用
//  这些库的话那就使用原始的socket(即C式的socket编程吧)。

/*    // 第5步：与客户端通信，接收客户端发过来的报文后，回复ok。
    std::string buffer[1024];
    while (true) {
        buffer->clear();
//        buffer = "";
        // 接收客户端的请求报文。
        ssize_t recvReturnValue = recv(acceptReturnValue, buffer, sizeof(buffer), 0);
//        ssize_t recvReturnValue = recv(acceptReturnValue, (void*) buffer.c_str(), sizeof(buffer.c_str()), 0);
//        ssize_t recvReturnValue = recv(acceptReturnValue, const_cast<char*>(buffer.c_str()),
//                                       std::strlen(buffer.c_str()) + 1,
//                                       0);
        if (recvReturnValue <= 0) {
            std::cout << "recvReturnValue=" << recvReturnValue << std::endl;
            break;
        }
        std::cout << "接受: " << *buffer << std::endl;

//        strcpy(buffer, "ok");
        buffer->clear();
        buffer->append("OK");
//        buffer = "OK";
        // 向客户端发送响应结果。
        ssize_t sendReturnValue = send(acceptReturnValue, buffer, sizeof(buffer), 0);
//        ssize_t sendReturnValue = send(acceptReturnValue, buffer.c_str(), strlen(buffer.c_str()), 0);
        if (sendReturnValue <= 0) {
            perror("send");
            break;
        }
        std::cout << "发送: " << *buffer << std::endl;
    }*/


    // 第6步：关闭socket，释放资源。
    close(serverSocket);
    close(acceptReturnValue);
}